from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from books.models import BookInfo
from .serializers import BookInfoSerializers

"""
get     获取所有数据
post    新增一条数据
get     查看详情
put     修改数据
delete  删除数据
"""

""" 基本是图类 APIView """
class BookViewSerializer(APIView):
    def get(self,request):
        # 1. 获取数据
        data = BookInfo.objects.all()
        # 2. 实例化序列化器
        serializer = BookInfoSerializers(data,many=True)
        # 3. 返回数据
        return Response(serializer.data)

    def post(self,request):
        # 1. 获取用户提交的数据
        data = request.data
        # 2. 实例化序列化器
        serializer = BookInfoSerializers(data = data)
        # 3. 验证数据，保存数据
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 4. 返回数据
        return Response({"msg":"添加成功"},status=status.HTTP_201_CREATED)


class BookInfoViewserializer(APIView):
    def get(self,request,id):

        # 1. 更具id获取模型对象数据
        try:
            book = BookInfo.objects.get(id=id)
        except BookInfo.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        # 2. 实例化序列器
        serializer = BookInfoSerializers(book)
        # 3. 返回数据
        return Response(serializer.data)

    def put(self,request,id):
        # 1. 根据id 获取模型对象
        try:
            book = BookInfo.objects.get(id=id)
        except BookInfo.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
        # 2. 获取用户提交的数据
        data = request.data

        # 3. 实例化序列化器
        serializer = BookInfoSerializers(instance=book,data=data)

        # 4. 验证数据，保存数据
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 5. 返回数据
        return Response(serializer.data,status=status.HTTP_201_CREATED)

    def delete(self,request,id):
        # 1. 根据id 获取模型对象
        try:
            BookInfo.objects.get(id=id).delete()
        except BookInfo.DoesNotExist:
            pass
        return Response({"msg":"删除成功"},status=status.HTTP_204_NO_CONTENT)


""" 通用视图类 GenericAPIView"""
from rest_framework.generics import GenericAPIView
class Book2ViewSerializer(GenericAPIView):
    queryset = BookInfo.objects.all()  # 指明使用的数据查询集
    serializer_class = BookInfoSerializers
    def get(self,request):
        # 1. 获取模型所有数据
        books = self.get_queryset()
        # 2. 实列化序列器
        serializer = self.get_serializer(books,many=True)
        # 3. 返回结果
        return Response(serializer.data)

    def post(self,request):
        # 1. 获取用户提交的数据
        data = request.data

        # 2. 实例化序列化器
        serializer = self.get_serializer(data=data)

        # 3. 验证数据，保存数据
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 4. 返回数据
        return Response(serializer.data,status=status.HTTP_201_CREATED)


class BookInfo2ViewSerializer(GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializers
    """查询一个数据"""
    def get(self,request,pk):
        # 1. 通过id获取模型数据

        # instance = self.get_queryset().get(id=pk)  # self.get_queryset().get(id=pk) === instance = self.get_object()
        instance = self.get_object()  # 当参数为pk的时候才能使用get_object()方法 ， 因为参数pk已经是在源码里面内置了，所以只能是pk

        # 2. 实例化序列化器
        serializer = self.get_serializer(instance)

        # 3. 返回数据
        return Response(serializer.data)

    def put(self,request,pk):
        # 1. 获取用户输入的数据
        data = request.data
        # 2. 通过id获取模型数据
        # instance = self.get_queryset().get(id=pk)
        instance = self.get_object()
        # 3. 实例化序列化器
        serializer = self.get_serializer(instance=instance ,data=data)
        # 4. 验证数据，保存数据
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 5. 返回结果
        return Response(serializer.data,status=status.HTTP_201_CREATED)

    def delete(self,request,pk):
        # 1. 通过id 删除数据
        # self.get_queryset().get(id=id).delete()
        instance = self.get_object()
        # 2. 返回结果
        return Response(status=status.HTTP_204_NO_CONTENT)


""" 

使用drf内置的模型扩展类[混入类]结合GenericAPIView实现通用视图方法的简写操作

from rest_framework.mixins import ListModelMixin获取多条数据，返回响应结果       list
from rest_framework.mixins import CreateModelMixin添加一条数据，返回响应结果     create
from rest_framework.mixins import RetrieveModelMixin 获取一条数据，返回响应结果  retrieve
from rest_framework.mixins import UpdateModelMixin更新一条数据，返回响应结果     update(更新全部字段)和partial_update(更新单个或部分字段，例如修改密码，修改头像)
from rest framework.mixins import DestroyModelMixin 删除一条数据，返回响应结果   destroy

"""
from rest_framework.mixins import ListModelMixin,CreateModelMixin
class BookMixinSerializer(GenericAPIView,ListModelMixin,CreateModelMixin):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializers

    """ 查询所有数据 """
    def get(self,request):
        return self.list(request)  # 可以进行查看源代码

    """ 添加一个数据 """
    def post(self,request):
        return self.create(request)  # 可以进行查看源代码

from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class BookInfoMixinSerializer(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializers

    """ 查看详情 """
    def get(self,request,pk):
        return self.retrieve(request,pk)

    """ 更新数据 """
    def put(self,request,pk):
        return self.update(request,pk)

    """ 删除数据 """
    def delete(self,request,pk):
        return self.destroy(request,pk)



"""
上面的接口代码还可以继续更加的精简，dr f在使用GenericAPIView和Mixins进行组合以后，还提供了视图子类。
视图子类是通用视图类和模型扩展类的子类，提供了各种的视图方法调用mixins操作

    ListAPIView = GenericAPIView + ListModelMixin           获取多条数据的视图方法
    CreateAPIView = GenericAPIView + CreateModelMixin       添加一条数据的视图方法
    RetrieveAPIView = GenericAPIView + RetrieveModelMixin   获取一条数据的视图方法
    UpdateAPIView = GenericAPIView + UpdateModelMixin       更新一条数据的视图方法
    DestroyAPIView = GenericAPIView + DestroyModelMixin     删除一条数据的视图方法组合视图子类
    
组合视图子类
    ListCreateAPIView = ListAPIView + CreateAPIView
    RetrieveUpdateAPIView = RetrieveAPIView + UpdateAPIView
    RetrieveDestroyAPIView = RetrieveAPIView + DestroyAPIView
    RetrieveUpdateDestroyAPIView = RetrieveAPIView + UpdateAPIView + DestroyAPIView

"""

from rest_framework.generics import ListAPIView,CreateAPIView


class BookModelView(ListAPIView,CreateAPIView):
    """ 源码内已经封装了get、post方法 """
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializers



from rest_framework.generics import RetrieveAPIView,UpdateAPIView,DestroyAPIView
class BookInfoModelView(RetrieveAPIView,UpdateAPIView,DestroyAPIView):
    """ 源码内已经封装了put、get、delete方法 """
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializers


"""
针对视图子类这种写法写法虽然已经省略了http请求，但是在开发通用5个api接口时，还是会出现需要2个类来实现5个接口的情况。

这主要的原因是2点:
1．获取多条数据与获取一条数据的http请求重复了。在django中依赖于请求方法来响应不同的http请求
2．部分接口需要pk值作为ur1地址。

drf为了解决上面的2个问题,提供了视图集和路由集。
视图集就可以帮我们实现一个视图类响应多种重复的http请求
路由集就可以帮我们实现自动根据不同的视图方法来生成不同参数的路由地址。
from rest_framework.viewsets import ViewSet # ViewSet是APIView的子类，是所有drf中的视图集的父类

"""

from rest_framework.viewsets import ViewSet

class BookViewSet(ViewSet):
    def book_list(self,request):
        # 1. 获取所有数据
        instance = BookInfo.objects.all()
        # 2. 实例化序列化器
        serializer = BookInfoSerializers(instance,many=True)
        # 3. 返回结果
        return Response(serializer.data)

    def book_create(self,request):
        # 1. 获取用户提交的数据
        data = request.data
        # 2. 实例化序列化器
        resializer = BookInfoSerializers(data=data)
        # 3. 验证数据，保存数据
        resializer.is_valid(raise_exception=True)
        resializer.save()
        # 4. 返回数据
        return Response(resializer.data,status=status.HTTP_201_CREATED)

    def book_listinfo(self,request,pk):
        # 1. 通过pk值获取模型数据
        instance = BookInfo.objects.get(id=pk)
        # 2. 实例化序列化器
        serializer = BookInfoSerializers(instance)
        # 3. 返回数据
        return Response(serializer.data)

    def book_update(self,request,pk):
        # 1. 通过pk值获取模型数据
        instance = BookInfo.objects.get(id=pk)
        # 2. 获取用户提交的数据
        data = request.data
        # 3. 实例化序列化器
        serializer = BookInfoSerializers(instance,data=data)
        # 4. 验证数据，保存数据
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 4. 返回数据
        return Response(serializer.data,status=status.HTTP_201_CREATED)

    def book_delete(self,request,pk):
        # 1. 通过pk 获取模型数据
        try:
            BookInfo.objects.get(id=pk).delete()
        except BookInfo.DoesNotExist:
            pass
        return Response(status=status.HTTP_204_NO_CONTENT)


""" GenericViewSet 通用视图类 """

from rest_framework.viewsets import GenericViewSet

class BookGenericViewSet(GenericViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializers
    def list(self,request):
        # 1. 获取所有数据
        instance = self.get_queryset()
        # 2. 实例化序列化器
        serializer = self.get_serializer(instance,many=True)
        # 3.返回数据
        return Response(serializer.data)

    def create(self,request):
        # 1. 获取用户提交的数据
        data = request.data
        # 2. 实例化序列化器
        serializer = self.get_serializer(data=data)
        # 3. 验证数据，保存数据
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 4. 返回数据
        return Response(serializer.data,status= status.HTTP_201_CREATED)

    def listinfo(self,request,pk):

        # 1. 通过pk获取模型数据
        instance = self.get_object()
        # 2. 实例化序列化器
        serializer = self.get_serializer(instance)
        # 3. 返回数据
        return Response(serializer.data)

    def update(self,request,pk):
        # 1. 获取用户提交的数据
        data = request.data
        # 2. 通过pk获取模型数据
        instance = self.get_object()
        # 3. 实例化序列化器
        serializer = self.get_serializer(instance, data=data)
        # 4. 验证数据，保存数据
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 5. 返回数据
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self,request,pk):
        # 1. 通过pk获取模型数据进行删除
        self.get_object().delete()
        # 2. 返回数据
        return Response(status=status.HTTP_204_NO_CONTENT)


"""视图集 GenericViewSet 通用类 + Mixins 混入类"""
class BookGenericViewSetMixin(GenericViewSet,ListModelMixin,CreateModelMixin,UpdateModelMixin,RetrieveModelMixin,DestroyModelMixin):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializers


"""
只读模型视图集
ReadOnlyModelViewSet = mixins.RetrieveModelMixin + mixins.ListModelMixin + GenericViewSet
- 获取多条数据
- 获取一条数据
"""
from rest_framework.viewsets import ReadOnlyModelViewSet
class BookReadOnlyModelViewSet(ReadOnlyModelViewSet,UpdateModelMixin,CreateModelMixin,DestroyModelMixin):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializers


""" ModelViewSet 模型视图集 """
from rest_framework.viewsets import ModelViewSet

from rest_framework.decorators import action
class BookModelViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializers


    @action(methods=["get"],detail=True)
    def login_log(self,request,pk):
        # http://127.0.0.1:8000/dome_views/book10/1/login_log/
        """ 用户登录历史记录 """

        # 可以通过self.action获取本次客户端请求的视图方法名[viewSet 提供的]
        print(self.action) # login_log

        return Response({"msg":"用户登录历史记录"})


    # 路由对象绘视图集生成路由信息时.品余生成5个基杰api接口这主要呆coute.r只识别5个混入类的原因
    # 而针对我们开发者自定义的视图方法，路由对象不会自动生成路由信息，
    # 所以下面这个login，如果希望被外界访问到，则必须通过action装饰器告诉路由对象要给它生成一个路由信息。
    # action(methods-["get","post"],detail = False,url_path="login")
    # action的参数
    # methods，列表，指定允许哪些http请求方法可以访问当前视图方法
    # detail，布尔值，告诉路由对象在生成路由信息时，是否要自动生成pk值，True表示需要，False表示不需要。
    # url_path，字符串，访问视图的url地址，如果不设置，则默认采用视图方法名作为访问后缀

    @action(methods=["get"], detail=False,url_path="user/login")
    def login(self, request):
        # http://127.0.0.1:8000/dome_views/book10/user/login/
        return Response({"msg": "登录成功"})




